字幕列表 影片播放 列印英文字幕 COLTON OGDEN: All right. Hello, everybody. My name is Colton Ogden. This is CS50 on Twitch. And I'm joined by Kareem Zidane. KAREEM ZIDANE: Hello, everyone. COLTON OGDEN: So, Kareem and I did a stream about-- was it last week or two weeks ago? KAREEM ZIDANE: Yep. COLTON OGDEN: On GitHub and git where we talked about what is GitHub, how do you actually use it and use it on your local machine? How do you then tie that into our repository on GitHub? Which is sort of the first part of the equation for a lot of modern development. But what are we going to talk about today that sort of extends that? KAREEM ZIDANE: Today we are going to talk about two very important concepts or terms in the dev ops world, namely continuous integration and continuous deployment, otherwise known as CI/CD. And just because of the context, we are also going to be talking about a little bit of testing techniques. COLTON OGDEN: Sure, yeah, very important things. You know, obviously as you're developing applications beyond just toy applications, getting into actually a business setting-- KAREEM ZIDANE: Yeah. COLTON OGDEN: --or even CS50 type-- a lot of CS50's apps and infrastructure is all sort of based around this idea of continuously deploying testing and integrating your apps onto their respective platforms. KAREEM ZIDANE: That's true. Yeah, so last time we actually talked about GitHub, as you mentioned. And we talked about the idea that these tools are very, very useful because we developers tend to make changes all the time. And so, it's nice to keep track of these changes and be able to toggle between or switch between them later on. Today, we're going to extend that by means of being able to ensure that our changes don't break our projects or anything that we have in our project already. And we're also going to be able to automatically maybe publish our project or deploy our project to several targets. If it's a website, for example, we can deploy this to Amazon, or to Heroku, or if it's a Python package we can deploy this to Pipeline, and so on. COLTON OGDEN: Yeah, because obviously if we're deploying our website, we make changes and we push them. We want to make sure that they don't break. KAREEM ZIDANE: True. COLTON OGDEN: The irony being that Facebook is currently at 503. KAREEM ZIDANE: Yes. COLTON OGDEN: Which we just saw earlier. So, let's see what we have in the chat today. We have a few people in the chat. We have a ForkDB, which I'm not sure if we saw you before in a previous stream. [? RahulNogBelecuras ?] is a regular. [? SashaCan't32 ?] says hello. MKloppenburg says "hey, everybody." MKloppenberg is a regular. And [? MajordFought ?] says, "hi, what is this session about?" This session's going to be about CI-CD. So, what's the first big topic that we want to bite off today? KAREEM ZIDANE: OK, do you want to switch to my-- COLTON OGDEN: Yeah, let's do that. So, let's bring up Kareem's screen here. KAREEM ZIDANE: All right. So, here's my terminal. And I'm going to start by writing my own sort of simple math library that has one function. And this function is going to test if an integer, a number, a positive integer, or non-negative integer, is prime or not. COLTON OGDEN: OK. KAREEM ZIDANE: And if you don't recall, a prime number is a number that's only divisible by itself and 1 only. So yeah, let's try to get started. So, I'm going to open a new file here. Call it MyMathLib.pi. COLTON OGDEN: OK. KAREEM ZIDANE: And I'm going to define a Python function called Is_Prime that takes in one argument, n. And then inside of that function, what I'm going to do is try to check if a number is prime or not. Now, mathematically, if a number is not prime, it has to have a factor that's less than or equal to it square root. COLTON OGDEN: OK. KAREEM ZIDANE: Right? So, I mean, you should probably trust me on that. But the mathematical proof for this is pretty simple. We're not really going to go through it right now. COLTON OGDEN: Yeah, you can't define something by something larger than half of itself, right? KAREEM ZIDANE: You can divide something by something-- COLTON OGDEN: That's why we take the square root, because we can't find a factor that's larger than its half. KAREEM ZIDANE: OK. I'm going to-- OK, I'm not sure I get that totally. But I'm going to trust you on this as well. COLTON OGDEN: That's the way I understand it. KAREEM ZIDANE: All right, I mean, yeah, sure. So, we can we can start by iterating through the numbers from i up to n, including the square root of n, which is the number that we're trying to figure out if it's prime or not here. COLTON OGDEN: So, from 1 until half of-- so, say 20-- it would be not half the square root in that case. It would be like-- KAREEM ZIDANE: Yep. COLTON OGDEN: 4.0-something. KAREEM ZIDANE: That's why I was puzzled when you said half of half. COLTON OGDEN: Yeah. Because there is another algorithm I thought where are they checked up to half of it. But I guess the square root makes sense. KAREEM ZIDANE: Right. So, we better not divide by 0. We better not divide by 1. So, we're going to start by dividing by 2 and then go up to the square root of n, which I believe is going to be in math, right? Import math. COLTON OGDEN: Yeah, I think so. KAREEM ZIDANE: I mean, we're going to figure this out if it doesn't work. So, square root of-- COLTON OGDEN: We got a couple messages in the chat, too. It says, [? RahulNog. ?] I can't properly stream because there's some buffering problem. Maybe network poor on 1080p? Yeah, possibly. Try, if there is an option, try downgrading grading the quality. ForDB says, "I'm here for the first time." And [? RahulNog, ?] they're there for the first time as well. So, thanks so much for joining us for the first time. KAREEM ZIDANE: Yeah. COLTON OGDEN: As we dive into CI/CD. Definitely check out our prior streams in the GitHub stream if curious. [? Nuanda333, ?] [? Asley, ?] says, "oh, that is so cool. Kareem the dream. We have a game between my friends to guess if the number is prime or not. Next time I will cheat using this." Yeah, definitely the cheat-y way to go. KAREEM ZIDANE: All right, sounds great. Yeah, all right. So, let's move on. So now we're looping through the numbers starting with 2 up to and including, presumably, the square root of n, in this case. And what we're going to do is check if n is divisible by i, in which case n remainder i is going to be equal to 0. In this case, we're going to return false, right? COLTON OGDEN: Mhm. KAREEM ZIDANE: Otherwise return true. How does that sound to you? COLTON OGDEN: Sounds good. KAREEM ZIDANE: All right. So, let's actually test this out. How would you test this out? COLTON OGDEN: I'd probably run it on a sequence of numbers that I've predetermined have a certain-- a certain set of numbers that I know are prime versus a set of numbers that I know are not prime. KAREEM ZIDANE: Exactly. So, I just fired up a Python interpreter here. I'm going to import my function. So from MyMathLib, import is prime. Now I have is_prime in scope. So, I'm just going to try to call in a bunch of numbers. So for example, 0-- whoa, OK. What's happening here? COLTON OGDEN: So, is_prime. Float object cannot be interpreted as an integer. KAREEM ZIDANE: That's probably because the square root function returns a float. And this expects an integer. COLTON OGDEN: Oh, yeah. KAREEM ZIDANE: So, let's do this. Let's switch it to an integer. OK, let's try it again. Import is prime from y-- the other way around. From MyMathLib. Import is_prime. And then try again, is_prime of 0. True. That's weird. COLTON OGDEN: OK, interesting. KAREEM ZIDANE: OK. COLTON OGDEN: So, did we not special case a 0, perhaps? KAREEM ZIDANE: Yeah, there seems to be a problem here. Well, it's saying that 0 is the prime, 1 is prime, 2 his prime, 3 is prime, 4, 5, OK, is 4 prime? Well, it seems to be buggy. So, the first thing that we-- it's a good practice. The first thing that we should do when we find a bug like this in our program is actually pinpoint this bug. Or in other words-- you know, you can you can imagine, every time I do something or try to fix a bug around a feature that I open up a Python interpreter like this and keep trying things like this. This is not really very time-efficient. Because I'm going to be doing this again and again. And this seems to be like a computer's problem. Right? COLTON OGDEN: So, you can maybe do what you just did in the loop, or something in a script, and just read your program over a bunch of them? KAREEM ZIDANE: That's true. COLTON OGDEN: Instead of manually typing them out, maybe. KAREEM ZIDANE: Yeah, I could I could definitely write a program that would test these automatically for me. Luckily though, Python has actually a testing framework called Unit Test. COLTON OGDEN: Oh, nice. KAREEM ZIDANE: That we could actually use. So, this stream is not really about Unit Test itself. But we're going to be exploring a bit of its features. Hopefully we'll explain the ones that we use while we're going through them so that they're clear to everyone. So, let's actually try this. So, in another file. I'm going to call tests.py. All I need to do to use Unite Test is import UnitTests, like this. And then create a class called-- I'm going to call it, in this case, to try to be descriptive, IsPrimeTests because I'm testing my [? s ?] prime function. And this class is going to extend UnitTest.TestCase. And by extend, this is actually an object-oriented programming concept. It basically means use features from the class UnitTest.testCase, COLTON OGDEN: You're basically making a new class called IsPrimeTests, which takes all of the behavior of test case, in this case. KAREEM ZIDANE: Correct, it's exactly that, yeah. It's based on UnitTest.TestCase in this case, which is another class defined in the unit test library. COLTON OGDEN: [INAUDIBLE] says that my audio is a little low. I just changed the sensitivity. Is it still a little bit too low? It does look like the audio levels are a bit low on it. Hold on, let me try-- whoops. Is that any better? Are we getting a little bit-- we're getting a little bit closer. I'm not sure why it's so low. Test, one, two, three. Sorry, my mic says it's at a good sensitivity level. I'm not sure. How's that? Is that any better? Oh, now it's in the red. OK, cool, cool. And then [? Gooliash ?] says, "hello, everybody." Hello, [? Gooliash. ?] Thanks for joining. [? RahulNog ?] says that he's having some issues with the resolution. We only stream up to 1080p. So, I'm not sure if maybe Twitch does on the fly encoding of the video to 720. I would have imagined that they have a streaming option. I think if I click on this-- let me see. Advanced-- no. KAREEM ZIDANE: Is it quality? Quality, maybe? COLTON OGDEN: Where do they that? Oh, quality auto. Oh, yeah, they only have-- it looks like they only first give you the 1080 option. I'm not sure if they do the-- I think they do the encoding later, such that you could watch the VOD at 720. The video will be up on YouTube for sure later. And it have 720, 360, all sorts of different options. Sorry that it's having a little bit of a bandwidth issue at the moment. ForSunlight says, "Aloha." ForSunlight, good to have you with us again. And then ForkTV says, "your stream is flawless." Thanks, ForkTV. Much appreciated. Here we go. KAREEM ZIDANE: [INAUDIBLE] COLTON OGDEN: [INAUDIBLE] KAREEM ZIDANE: All right, sounds good. COLTON OGDEN: All right, cool. Sorry about that. Go ahead, continue. KAREEM ZIDANE: OK, so, I have my class. I'm going to use this class in a moment. But let's first add something. If_Name=main, you've run Unit Tests. UnitTest.main, right? COLTON OGDEN: OK. KAREEM ZIDANE: So, what this does is it says if I've run this script-- which is called Tests.pi, that we just created-- from the command line-- like I do Python Tests.pi-- then run the script, run the code in the main function. COLTON OGDEN: This is kind of where you'll have what you were doing before, manually iterating through the different Is_Prime function calls. KAREEM ZIDANE: Kind of. COLTON OGDEN: Manually at the [INAUDIBLE]?? KAREEM ZIDANE: Yeah, kind of. OK, so how do we add a test case with Python's Unit Test? So, it turns out that any function that starts with a keyword "test" is actually considered to be a test by default. So, in this case, I'm going to define a new function called test_zero. And this one just going to take one argument [? self ?] because, annoyingly, that's how Python works. It needs a self-argument if you're defining a method inside of a class. If you're not familiar with this, perhaps maybe learn a little bit more about object oriented programming in Python. COLTON OGDEN: We could maybe do a stream about it in the future. KAREEM ZIDANE: Yeah, maybe. But for now, yeah, let's take it for granted that self needs to be there at least. And it turns out that Unit Test actually has a bunch of built-in functions that we could use for testing other stuff. So, we could use certain functions to test if something is equal to something else, or if something is true, or if something is false, and so on. And so, in this case we're going to do exactly that. So, we're going to say Self.AssertFalse because we expect that 0, when past is prime, returns false, right? So, we're going to insert that false of is_Prime(0). Now, Is form is not really defined anywhere here. So, I'm going to just import it like I did before. COLTON OGDEN: Right. KAREEM ZIDANE: So, I'm going to do from MyMathLib import Is_Prime. COLTON OGDEN: Somebody in the chat says-- [INAUDIBLE] "is there a typo in the parent class name?" KAREEM ZIDANE: Yep, that's correct. It should be TestCase, not "test cast." COLTON OGDEN: Thanks for that, [INAUDIBLE].. KAREEM ZIDANE: Thank you so much. COLTON OGDEN: [? Goulia74 ?] says "maybe test case." And then [? LincePutaWire ?] says "Unit Test?" KAREEM ZIDANE: Yes. COLTON OGDEN: Yeah. KAREEM ZIDANE: So, unit testing is actually a testing technique that's very, very popular and used in a lot of projects. And it also is supported-- a lot of languages actually have built-in Unit Test libraries or frameworks. And unit testing is basically the idea of dividing your program or library, or your software in general, into units, like modular units that you are able to test each of them separately. So, this is the basic idea of what a unit test is. COLTON OGDEN: So, like, modularizing the testing of our program. KAREEM ZIDANE: Correct, yeah. Yes, basically splitting your program into testable units and then testing these. COLTON OGDEN: [? Nasquito ?] says hi. Hi, [? Nasquito. ?] Thanks for joining us today. KAREEM ZIDANE: Yep. Thank you. All right, so let's move on. So, the way to run this is-- by the way, I'm using a text editor called Vim in this case. But you're free to use whatever you want. You don't have to use this. COLTON OGDEN: Your Vim looks nice. Your Vim actually it looks like the s code almost, like a modern editor. Some Vim set-ups look a little bit more arcane. KAREEM ZIDANE: I know you're a big fan of VS Code. I haven't used it, unfortunately. But yeah, you can use VS code. You can use Atom. You can use any number of text editors. COLTON OGDEN: Your Vim [INAUDIBLE] is nice. KAREEM ZIDANE: Thank you so much. All right, it's not mine, actually. I just downloaded it from somewhere. All right, so the way to run these tests would be by running Python, test the pi. And, as expected, I see a bunch of weird output here. Namely, I see an f on the top left corner. And this indicates that a test has failed. And a test can, I think do or be in one of three states. It can pass, in which case it would show a dot. And we'll see an example of that. It can error, in which case there might be a syntax error in your code. Or it can fail, in which we got a result but the result is not the one that we expect it to be. So, in this case we we passed 0 to h prime. And we got true. But we are expecting false, which is indicated by a searching error right here. So, it tells us that true is not false. COLTON OGDEN: And that's how we got the f, because we inserted false. KAREEM ZIDANE: Correct, exactly. So, how do you fix this? Let's go back to our code. Now that we pinpointed the bug that we have with the test case-- and this is just to ensure that this bug never happens again once we fix it. So, no matter who changes our code later on, we're going to run these tests every time. And if they fail, then there's something wrong. So, how do you propose fixing this bug? COLTON OGDEN: Well, I see that you're returning false immediately at the first time-- well, OK. So, let's see. For i in the range of 2 to that number. So, the problem is that it's going to start at 2. KAREEM ZIDANE: Right. COLTON OGDEN: Wait, does it start? Yeah. It's inclusive, right? So, it'll start at 2. KAREEM ZIDANE: Yep. COLTON OGDEN: So, it doesn't account for the case of 0 or 1. KAREEM ZIDANE: Right. So, that's exactly right. So, I'm going to check if n is less than 2 initially. And then return-- what-- false immediately. COLTON OGDEN: You're going to want to return false, yeah. KAREEM ZIDANE: So, once again, for those of you who didn't follow, we are essentially checking if n, initially, is less than 2. In which case we say, no, this is not prime. And we return false immediately. Otherwise, we continue and do our check. So, there is one more bug here. But let's make sure that our test passes first. Right? So, let's do Python test.pi again. And our test passed. COLTON OGDEN: Nice. KAREEM ZIDANE: All right. So, let's suppose I wrote a program that depends on my library, or I'm testing stuff again randomly. And I happen to find another bug. So, let's do this again. So, from MyMathLib import Is_Prime. And do Is_Prime-- you know, I'm doing a bunch of stuff. 1, OK, works as expected. 2, its prime, all right. 3 is prime. 4 is prime-- no, it's not. COLTON OGDEN: I don't think 4 is prime. KAREEM ZIDANE: All right, so, the first thing that we should do again is pinpoint the bug. So, we're going to add another function, test function here again. Do a test-- 4, for example, Self.Assert. False Is_Prime(4). COLTON OGDEN: OK. KAREEM ZIDANE: Right? Now we're going to run the tests again just to see them failing first. As you can see, there is an f and a dot. As we mentioned, the dot-- COLTON OGDEN: So, just write it all in one long string? KAREEM ZIDANE: Exactly. Yeah, we're referring to the very first line here in the output. So, the f indicates that one test fails. COLTON OGDEN: You want to see a long string of dots. KAREEM ZIDANE: Exactly, you'll always want to see dots. If you're not seeing dots, there's something wrong. And a dot means the test succeeded or passed in this case. COLTON OGDEN: OK. KAREEM ZIDANE: And it's telling us again that true is not false. And it's telling us that this is on test.pi line 11. If I open this, I'll find the Self.Assert false is prime 4. COLTON OGDEN: OK. KAREEM ZIDANE: All right, so the bug actually-- I'm not going to put you on the spot again. But the bug actually is, if we open our code again, is that actually the second argument to range is not included in the range. COLTON OGDEN: Oh, yeah, yeah, yeah. KAREEM ZIDANE: It doesn't include the square root. COLTON OGDEN: So we have to add 1 to it. KAREEM ZIDANE: Exactly, so we have to add 1 to it. So in this case, we're going to add 1 to this. And hopefully, if we didn't do anything wrong, run the test again. They pass. COLTON OGDEN: Nice. KAREEM ZIDANE: All good. All right, so we can keep doing this. We can keep using our program. We can keep playing with it and trying to figure out if there are bugs or not. One thing that's probably worth mentioning though, is that a function like IsPrime can take any number of-- an infinite number of inputs. So, it's not really something practical that we would expect to write an infinite number of test cases. Because that's practically not possible, right? COLTON OGDEN: Right. KAREEM ZIDANE: So, in cases like these, we would always try to choose inputs that are representative in this case. COLTON OGDEN: Yeah. KAREEM ZIDANE: So, try to crash our program, in other words. So, I would try negative 1 for a negative number, negative 2 for a number that would have been prime if it was positive. A square root that's even, a square root that's odd, and so on. So, I try to write a bunch of test cases that represent different kinds of inputs, and test my programs on it. That's pretty much the best that I can do. COLTON OGDEN: Corner cases and sample like normal sample points. KAREEM ZIDANE: Exactly. I believe I have a few test cases here. And let's see. Let's move [? this ?] tests to original. [? To ?] tests1.py. So I've written in advance a bunch of test cases testing zero, testing one. Notice here I'm testing that two is prime. So solved it assert true, in this case, not assert false, because I expect the return value true in this case. Same thing for three, four is false, testing in eight, testing in nine, which is-- sounds like a prime number, but it's actually not. So a bunch of good test cases. I'm just going to try to run these again and they all ran as expected and succeeded. COLTON OGDEN: Victory. 4Sunlight adds-- says, "Can we test our random number generators this way?" KAREEM ZIDANE: I'm not sure what you mean. COLTON OGDEN: The way-- I guess some way that I would interpret that is testing to make sure the random number generator actually generates an even distribution of random numbers maybe. So certain normalizing the distribution of 1,000 random numbers. But aside from that, I can't think of any other use cases off the top of my head. If that's what you were referring to, 4Sunlight? KAREEM ZIDANE: Yeah, please elaborate if that's not-- if that doesn't answer your question. Maybe we can look into that. But any other questions on the test cases that we wrote or the code in general? COLTON OGDEN: 4Sunlight says, "Yes, exactly. You're a great interpreter. Thank you very much." KAREEM ZIDANE: Awesome. COLTON OGDEN: Very kind of you. KAREEM ZIDANE: So it's still kind of painful though to have to write the test step manually or have to run the test manually every time we make a change to a code. So this is what actually CI, or continuous integration, solves for us. Continuous integration will allow us to automatically run these tests once we push our code to GitHub, in this case. Some of you might be wondering, is there a way to run these tests locally before committing even? Yes. As far as I know, I haven't used them before, but there is something called git hooks that you could use to essentially run a script, or in this case, our test, the py script, to actually do something before committing or do something when various events happen. So the first thing that we need to do is actually we're going to be using a service called Travis CI today, and Travis CI is a continuous integration, a continues deployment service that you can log into using your GitHub account. So I'm logged in already here. And once you log into Travis CI, you're essentially authorizing them to read or write to some or all of you repositories on GitHub. Do you have a question? COLTON OGDEN: Me? KAREEM ZIDANE: Yeah. COLTON OGDEN: Oh, no. I'm just looking at the-- I have the-- I'm basically following along with you and I'm reading your-- KAREEM ZIDANE: Let me actually [INTERPOSING VOICES] KAREEM ZIDANE: --maybe this is not readable at all. So if I go to Profile, for example, after logging in, if I go to Profile/ my username, I should see a listing of my repositories that I have. COLTON OGDEN: Airlines, Airline0, Airline1? KAREEM ZIDANE: Yeah, these are from Brian's web course. We gave a course in the summer with Doug. He was teaching the course. COLTON OGDEN: Wow. KAREEM ZIDANE: So we were using these. So in this case, I have a new repository called CICD Stream in my GitHub, and what I'm going to do is actually, first of all, git inut this. And then add-- COLTON OGDEN: Throwback to our prior stream if anybody wants to know how git works. KAREEM ZIDANE: Yep. I actually planned to do this beforehand, but I forgot. But let's add this new remote. So I'm just linking my local folder or my local repository to the GitHub one that I just created. So I'm going to do-- add the remotes repository, which is called CICDStream.git. Now I see all these files. Let me rename test1.py, which is a more complete one to test the py, because I don't need this anymore. So now my test.py looks like this, which is the one that has a few more test cases. Let me actually ignore as well, so let's ignore the pycache1 because I don't need it. So I'm going to echo pycache2.gitignore. COLTON OGDEN: It looks like Goulia74 has a question for you as well. KAREEM ZIDANE: "So I skipped the beginning. Is Selenium-- am I getting a true line--" yeah. Let me reread this, because I read it in my head instead. "I skipped the beginning. Is Selenium at the beginning of the line in the terminal of name-- of your virtual end or does it somehow appear when you use Selenium?" So this is yes. As you expected, this is a virtual environment. We are going to be using Selenium later at the end of the stream. I should have deactivated this to avoid distraction. So let me do this now. But, yes, Selenium is a virtual environment. So let me get out of this virtual environment. Now there's no Selenium. This never happened. So let me do git status again. I have all these files. Let me actually ignore a couple more files. So let me ignore mymathlib.py.original, which is one that I wrote beforehand just in case I forgot anything. I have the files that I care about. I'm going to add all the files that I have, git status again, confirm that they are in my staging area, my index, and then do a git commit. Say this is my first commit and then git push. And of course, it's asking me where to push to. And I'm going to say push to the master branch on GitHub and also track this local repository or track this remote, sorry, track this remote branch with my local branch, in this case, which is also called master. So I'm going to do this. Now, if I reload the page I should see my code-- all great. So how do we tell Travis CI to run our tests automatically once we push? If we look at the Travis CI documentation, we are going to find that to get started, we need to create a file in our repository, in the root of our repository, the top level of it, called .Travis.yml, so let's do that. .Travis.yml-- creating a new file. And .yml actually stands for YAML, which is a configuration language or a language that's often used for configuration. It's very similar in spirit to JSON, if you're familiar. I think it's more human readable and I think supports more fancy stuff than JSON as well. So it's just going to be a bunch of key value pairs that have a certain hierarchy. COLTON OGDEN: I sort of think of it as like the Python version of JSON almost. KAREEM ZIDANE: Yeah, kind of, yes. COLTON OGDEN: It reminds me if Python made its own version of JSON. KAREEM ZIDANE: Yeah. I think Python does use a configuration language. I'm not sure what it's called though. There's a really popular format with Python applications. Anyway, we're not going to go into this right now. But to get started, we need to say what the language that we use in our project is. In this case, language is Python, and we can optionally specify also which version of Python. I'm just going to be using Python 3.6, but you're free to use something else or even more than one version of Python. And there are two key steps in this case. One of them is install. And the install step is responsible for essentially installing your application itself, if it's installable. So in this case, if I'm creating a Python package, for example, I would do PIPinstall my package name, or PIPinstall. To install the current directory. In this case, I don't really have anything to install yet, so I'm just going to skip this and say true. I don't need to do anything. The second key step is the script step, and the script step is going to be the one or more commands that we need to run in order to test our program. So do you recall what this comment was? COLTON OGDEN: Pythontest.py, right? KAREEM ZIDANE: Yep, tests.py. So this is how we tell Travis, hey Travis, once our code is pushed to master in this case, run Pythontest.py first, and either if the build succeeds or if the tests succeed, make the build succeed. Otherwise, make the build fail. So we actually didn't demonstrate something. So let me go back for a bit. This is, by the way, I think this is the minimum that we need in this case. So all goods, a bunch of key value pairs. First of all, we specify the language. It's Python. We specify the Python version, which is 3.6 in this case. We say that we don't need to install anything. We don't need to install our package, because it's not really installable in this case. And we run the tests this way, by running literally Pythontest.py. You have a question? COLTON OGDEN: Yeah. MajorDefad says, "What advantage do we get from having the code tested online after pushing and not locally?" KAREEM ZIDANE: We could have it tested locally as well. Most people-- so the typical use case for this is that you would be working on a separate branch, so you would be fixing a bug, or adding a feature, or refactoring something on a separate branch. And the ideal case for this would be to do whatever you want on this branch, always push frequently to sync up the state of your GitHub repository with your local repository just in case you want to fetch this somewhere else, or you want to-- or something happened to your local code, so you have a copy on GitHub. And then you can actually have Travis test on this branch before actually merging to master. So master is usually-- always should be in a reasonably good state. So we should never merge like half the amount of changes into master, or know that something is broken, but still merging it to master. So the idea would be to separate these into two separate branches, commit and push on my separate branch as many times as I want, have the tests run automatically, and you can actually make GitHub force the case-- that's only when the test pass on this branch-- merge it into master. COLTON OGDEN: And so we can also deterministically ensure that we are testing if we have it automated. KAREEM ZIDANE: Yeah, definitely. Yeah, so this is also one other thing. I'm not quite sure about how git hooks works. But suppose you and I are working on the same repository right now. I have a bunch of git hooks that run the tests automatically, but you don't. So this is some sort of way to enforce that the tests are run for everyone. Another advantage of running the tested lines is the unified environment. So when we run all these tests on Travis, all the tests are literally only run in the Travis environment and not Colton's environmental or Kareem's environment, which might be different in this case. So we went to make sure that the tests work in the Travis environment, which is ideally-- you're going to be the same as our production environment, whatever that is. COLTON OGDEN: Makes sense. KAREEM ZIDANE: I hope that answers your question. And I think that's all what we need to do in this case. The thing that I forgot to show earlier was that, if we run Pythontest.py again, if all the tests succeed-- COLTON OGDEN: Actually, I see seven dots there. KAREEM ZIDANE: Exactly, yeah. So if we-- this is how we print the exit code of the previous command. So if we check the exit code of the previous command, this is going to be zero, which by convention means that the previous command ran successfully. If we break our program again-- let's actually remove this for now. And then try to break it again, we see a bunch of errors. I think if we do-- if we print the exit code again right now it's going to say something that's other than zero, in this case one, which means the command failed. COLTON OGDEN: And the question mark, dollars sign variable, that's the last return code? KAREEM ZIDANE: Yes. COLTON OGDEN: Given to you, the shell? KAREEM ZIDANE: Yes. This is an environment variable, if you're not familiar, that automatically for us stores the exit code of the previous comment. COLTON OGDEN: Nice. It looks like FungusStorba is tossing the Bob Ross emoji there. So thanks for that. MajorDefad says, "Works on my machine, and yeah, I just cleared out. Thanks." KAREEM ZIDANE: Yep, that's a real concern. It does work on my machine, but don't work on Colton's machine. We can always ensure that this is not a problem by ensuring that it only works in the Travis environment, which is neither your machine or my machine. COLTON OGDEN: And that's the last point too, before it actually gets sent off to whatever server your app might be built on or hosted on, rather. KAREEM ZIDANE: Exactly, and ideally, these two environments should be pretty much the same. But recently a lot of people have been using Docker, and I think Travis does have support for Docker. Probably not ideal, but Travis does have support for Docker, a bunch of other CI/CD services, like CircleCI, Jenkins, GitLab, CodeShip, whatever. All of these also have I think support for Docker as well, and Docker actually solves this problem as well, tries to minimize the differences between the testing environment and the production environment. COLTON OGDEN: Makes sense. KAREEM ZIDANE: So now that we know that the exit code is success if all tests pass and something else failed-- a failure code if one or more tests failed-- Travis actually uses these exit codes to determine if the build succeeded or failed. So it's going to run your command, which is the value of the script key, in this case, Pythontest.py. And if the exit code for that is not zero, it's going to fail the build. So let's actually demonstrated that. Let's, first of all, add our changes. So let's get, add everything, excuse me, and then git push to master. Oh, because we didn't commit. So we should get commit first. Let's say, enabled Travis and broke tests, push. So how do I follow this? Theoretically, if I go to the same-- Travis-CI.com/myusername/repositoryname, which is CICD Stream, I should see a build log. Which I don't, in this case. Let me zoom this out a little bit. Yep, so if I click on Build History-- eventually it's going to appear here. But if I click on Build History, I see that there's a build that's started here and it's listing some information about my commit that I just made. COLTON OGDEN: Yellow, meaning that it's in progress? KAREEM ZIDANE: Yes. Yellow means it's currently running. And if we scroll down a little bit, we can see the build log, what's happening during this build. If we click this little green thing on the top right corner, it's going to essentially have us follow this log by default, so just to avoid having you keep scrolling manually. COLTON OGDEN: So they build like a little custom environment, like a configured build environment every time you want to trigger a new build? KAREEM ZIDANE: Correct, yes. So they essentially, as we say, sandbox these tests, in this case. COLTON OGDEN: Because I noticed it said stuff about like installing Ruby and different other-- no JS. It looks like they installed quite a lot of stuff. KAREEM ZIDANE: Yeah, correct. So there are a bunch of standard environments that-- a bunch of options that you could choose from. I didn't want to dive too deep into the details of how Travis works in this stream, but the idea is that you can think of it as launching a very lightweight virtual computer or virtual machine, a container actually, in this case, if you're familiar. And then cloning your code inside of it and running the commands that you specify inside of it. So every time, yes, every time you push to GitHub, every time Travis CI build this trigger, it's going to run in actually a brand new environment for you. COLTON OGDEN: Cool, make sense. KAREEM ZIDANE: So we see the build turn into red, which is usually bad, in this case. And if you scroll down, we can see the log of why this build failed, after skipping all these details about installing software that we don't really care about now. And we see something very similar to the log that we saw when we ran Pythontest.py. COLTON OGDEN: It's just like they're running their own version of your environment and just pretty much copying the same algorithm. KAREEM ZIDANE: Exactly, and here's the command that we specified as the value of the script key, Pythontest.py, and we see two Fs here. Two tests failed, because one is thought to be prime, but it's not, and same thing for zero. COLTON OGDEN: Make sense. We've got a couple messages on the chat. So Gason says, "Interesting subject. I sent you my resume. I hope you would take a look, because it's interesting." Yeah, again, per the chat we had last time, CS50 is not actively hiring now. And I'm actually not in charge of the hiring process, but I'll definitely take a look at it just to see what you got in there. Richard says, "Thank you, guys, for doing these streams. They are really explanatory." Thanks for joining us. I appreciate that you are finding the content helpful. And 4Sunlight says, "Colton, would you have slides or any kind of CS50 notes if we are newbs and want to have some idea of the content?" Do you mean CS50, like the actual course notes or do you mean the stream-related notes? I know that we do have-- well, at least I do strongly believe we have notes for the course. For these streams, we don't really have notes, per se, but we do typically upload content to GitHub. And are we going to have this on GitHub, the CI? KAREEM ZIDANE: Yes, if it's actually on GitHub right now. So if you go to GitHub.com/KZidane/CICDStream, that would be a public repository and you should be able to see things right now. COLTON OGDEN: I think that's kind of like the-- usually what we have in terms of a support structure for the streams. They're kind of sort of done on the fly, a little bit looser. We don't really necessarily adhere to a strict set of notes, per se. But yeah, GitHub and the video is probably what we have. Maybe in the future for a more structured presentation we might have notes. I know I personally don't typically use notes or slides, but we'll keep it in mind. I'll ask people if they want to start doing that. KAREEM ZIDANE: JefferyHughes says, "Combining Travis and containers, is it a good practice?" So Travis gives you the option to use containers or not. Is a good practice? I would definitely use containers if I can, because they are more lightweight than virtual machines. But Travis also gives you the option to run a full fledged virtual machine, which is usually slower, in this case, but has its own advantages as well, so maybe check the documentation for that. "Sorry, because I didn't hear your answer. I would like feedback on the resume, friend." COLTON OGDEN: Yeah, again, Gason, I'll take a look at it when I can, but CS50 is not actively hiring at the moment. So I can't say that we'll do anything, take any steps about it, but I can take a look at it when it have some time and I'll give you some feedback. KAREEM ZIDANE: So let's actually see this build succeed after fixing our error, which we just broke-- after fixing our code, I should say. So let's go back to my mathlib library, remove these, run the tests again to be sure that everything's OK. Git status, git add mymathlib, git commit, fixed-- I don't know-- less than two, git push. And then within a second or two, I should hopefully see this user interface changing, running a completely new build for my new commit that I just pushed to GitHub, and hopefully succeeding if all this passed, which they did, locally, in this case. COLTON OGDEN: That's why it typically takes a long time, because they have to recreate that whole environment every time? KAREEM ZIDANE: Excuse me, yes. Sorry. So yes, if I click on Build History here, I should see the new build created. And if I click here-- usually it updates the current tab as well, but it seems to be a little bit slow in this case. I'm going to follow the log and let's see what happens. So it's creating a brand new environment, like you mentioned. It's fetching its own packages, installing some software that's preinstalled in this environment. And you can see that it ran our tests here and that all of them passed. COLTON OGDEN: Nice. KAREEM ZIDANE: And the exit code was zero. And then if we scroll back up, we see green right now, which usually means good. COLTON OGDEN: Nice. KAREEM ZIDANE: What else can we do? Travis actually has a lot more features than what we just introduced. So I actually didn't plan for this, but let's actually try to answer the question that we got earlier about running the tests remotely and having GitHub force, actually merging only if all objects succeeded. So let's do this on the fly. Hopefully nothing breaks. So I'm just going to-- COLTON OGDEN: That's famous last words right there. KAREEM ZIDANE: Yeah. So I'm just going to create a new branch here by using git checkout-b, and let's say new feature. This is the name for our branch, "feature." And let's actually suppose we're working our branch. We broke something again accidentally. So I'm going to break these again. I'm going to do git status. I'm happy with these. [INAUDIBLE] see my changes. I'm happy with these changes. Git add my file, get commit, added new feature, and accidentally broke something else. And then git push this to GitHub using git push-u origin new feature. So you'll notice that if we switch back to Travis, hopefully it triggered a new build for the new feature branch, as we see here on the top left-hand side. And what we expected, this build is going to fail. So while this build is running, let's actually change something in the repository settings. So if you're an administrator over your repository, if you're an owner, you can click on Settings, and I believe Branches on the left, and then Add Rule. And then up here it says, "Apply rule two." We can say master, we need to apply these rules to master, and I believe it's this option-- "Require status checks to pass before merging." COLTON OGDEN: So this is our new feature branch. So you're basically saying, before we can merge this new feature into master, which is usually our main source of truth-- KAREEM ZIDANE: Exactly, so that's essentially what most people do. They have their own one or two branches that are the main branches. master could be or usually is one of them. And the idea is allow people to work on their branches, do whatever they want with them, even people that are contributors to your repository, they'll have access to it. Allow them to do whatever they want to their branches. Eventually, they're going to open pull requests to try and tell you, hey, these are a good set of changes. Maybe you should consider them, consider merging them into master. And what you can have GitHub do for you is actually enforce these checks to pass before actually being able to merge them. COLTON OGDEN: So like a fail-safe. KAREEM ZIDANE: Exactly, yes. This is actually a huge time-saver, because imagine you have a very popular open source repository on GitHub and a bunch of people are trying to contribute to it. So you're going to have a bunch of pull requests open and you can just ignore pull request that fails the tests until they fix it. COLTON OGDEN: You don't have to go through PR, after PR, after PR that breaks. KAREEM ZIDANE: Exactly. Yes, and GitHub has usually-- there's a UI for this that we're going to see hopefully very soon. COLTON OGDEN: MajorDefad is asking, "So what happens on the GitHub side?" Hopefully this is addressing that question, because now we are digging into how to actually integrate Travis and GitHub together. KAREEM ZIDANE: So they are actually integrated automatically. You don't really have to do anything special to integrate Travis and GitHub, and that's one of the nice things. So what internally happens is that GitHub is going to use an API for Travis CI to check for the build status of the commit that we just pushed or the branch that we just pushed. And Travis is going to reply and say, hey, this build succeeded, or this build failed, or this build's still running, and then GitHub takes these results and processes them by either preventing you from merging, or allowing you to merge, and so on. COLTON OGDEN: And it visually tells you in the merge UI, oh, it didn't pass the Travis test, so you can't actually merge it. KAREEM ZIDANE: Yes, that's absolutely true. COLTON OGDEN: If you want to get your password manager, I can bring that. KAREEM ZIDANE: Yeah, if you don't mind. Just entering my very short password here. COLTON OGDEN: Kareem123. KAREEM ZIDANE: Exaclty. So I confirm this. Now, if you can switch back. Everything is OK, everything looks good. It's created my rule up here. Now, let's go back to our repository and receive this new branch, new feature branch that we created right here. So I can create pull request from this branch to try to merge it into master, as we see here on the top left, create pull request. And then notice if I scroll down, it's showing a Travis icon, and it already figured out that the build failed, showing me a red x here on the right. And if I want more details, I can probably go to More Details, and go to the build itself in Travis, and figure out why the build failed. Now, this might be a little bit confusing, but because I'm an administrator on this repository, I'm able to merge anyway. But if you're someone who has only write access, you would see this button disabled, in this case. So now that we've demonstrated this, I thought we could do one more cool thing if we don't have any questions. COLTON OGDEN: Looks like GaloshCanon is saying, "Hello, anyone familiar with Java? I have a problem that I'm unable to solve." This stream, I don't think we'll have time to look into Java. It's not really a super freeform stream. But definitely, if you're not in the CS50 Facebook group already, go to the CS50 Facebook group and try asking a question there. They might be able to assist you with that. KAREEM ZIDANE: I see also ForkDB asking me to show the exception. Yes, sure. If we go to the build and then scroll down, down, down to the bottom-- COLTON OGDEN: I think you might be referring to Galosh. KAREEM ZIDANE: Oh, OK, I misunderstood. COLTON OGDEN: Yeah, because Galosh also wrote after that he's got his exemption. KAREEM ZIDANE: That makes sense. COLTON OGDEN: It looks like you're using an unreferenced variable based on what the output is in the thing there. So make sure that you're not referencing a symbol that you didn't define. KAREEM ZIDANE: So let's actually explore a bunch of features in Travis itself. So if you click on this More Options up here-- of course, you have the option to restart the build without clicking on that. But if you click on that and go to Settings, you also have the option to disable build push branches. So sometimes you actually want to trigger the build manually if you want. And in this case, this option allows you to disable triggering builds automatically when you push branches. COLTON OGDEN: Generally, you usually want to, right? KAREEM ZIDANE: Yeah. COLTON OGDEN: Because you want to automate that process. KAREEM ZIDANE: Usually want this on, but in certain cases, you might want to disable any builds from being triggered when you push something and just be able to trigger them manually, which Travis allows you to do. Same thing for a build push pull requests. So if you have any pull requests open, also Travis is going to automatically trigger builds for them. You can limit concurrent jobs, and so on. This feature down here on the left, Auto Cancel Branch Builds, this is, you can imagine a scenario, where you push too quickly, so it triggers two builds, but you really care about the last build. So this allows you to cancel any running builds before running a new build, if that makes sense. Same thing for pull requests here. Down here we see environment variables. And if you're not familiar, excuse me, if you're not familiar with environment variables, they're essentially, as you call them, shell variables, which are variables in the same sentence, as we have variables in programming in Python, except that they are usually used to influence or change the behaviors of certain programs. For example, Make considers certain environment variables and changes its behavior based on their values or storing maybe secret information, like API tokens, or passwords, and so on. So Travis allows you to also add environment variables and their values. It also allows you to disable showing them in the build log, in this case, in case they are secrets or passwords. You don't really want to show them in the log. COLTON OGDEN: Probably not. KAREEM ZIDANE: And lastly, there is a clone job. You can set or configure Travis to automatically trigger builds, no matter you push something or not, every once in a while. So in this case, I could configure Travis to trigger a build automatically monthly. I would imagine this is useful for status checks or something. COLTON OGDEN: Something that interacts with other APIs? KAREEM ZIDANE: Exactly, yeah. So you want to make sure that-- to see if your website is up or not. It can be down for some reason without you pushing anything, so you could run a bunch of tests and have Travis notify you if something wrong happens. COLTON OGDEN: JefferyHughes says, "I always come late to the CS50 live streams. Is there any schedule for the future ones?" Not a formal schedule just yet. Probably we'll have-- it'll probably be the case that we always do Friday at 1:00 PM Eastern Standard time, but it's not hard set in stone yet. During the winter break, there will probably be much fewer, if any, streams, and then we'll have a more consistent schedule starting January 2, in which case I think what we'd like to do is something like Monday, Wednesday, Friday at 1:00 for a few hours, a couple hours every week. But it's kind of-- we're kind of still developing it, so let us know-- everybody, let us know-- what the ideal time is. We're thinking 1:00 PM is kind of a good time to cover the United States and a lot of the world, but we realize that it's going to be hard to get a perfect time for everybody, just given how disparate folks' schedules are and where people are in the world. But short answer, we're working on a schedule. Long answer is it's hard to-- a little more complicated. KAREEM ZIDANE: Yeah, but you can always subscribe to our events on Facebook, or wherever you post them, and get notifications-- COLTON OGDEN: That's true. KAREEM ZIDANE: --like someone [INTERPOSING VOICES] COLTON OGDEN: On our Facebook, we do keep a tally of-- or keep a schedule of all the upcoming Twitch streams, at least the ones that we know about, and we generally have a couple weeks' worth scheduled in advance. So if you're not already following our CS50 Facebook account, definitely do that-- the actual proper CS50 page, not the group necessarily. But join the group as well, because we also post the events there. LincePutaWire says I received the notification in his email, or in his or her email. Galosh says, "On my job is Python. Junior web dev, we use Jenkins. Travis just looks not as scary and has a way less monstrous UI." KAREEM ZIDANE: I haven't tried Jenkins myself, but a lot of people mention to me that Travis CI is more friendlier than Jenkins. They certainly-- I would expect them to do the same thing, essentially maybe using different set of configurations, different set of name, key value pairs, different file names, and so on. COLTON OGDEN: Maybe their UI is just a little bit different. KAREEM ZIDANE: Yeah, but conceptually they should be the same. I think also some CI and CD services allow you to do these configurations in the web UI itself. In this case, Travis requires that Travis is the YAML file, as we saw, but some of them actually allow you to do this in the web UI. I believe there's also a new feature of GitHub, called GitHub Actions, that's actually going to do a very similar thing. So yeah, it's in beta right now I think, so we're looking forward to that as well. COLTON OGDEN: A potential replacement for Travis? KAREEM ZIDANE: Exactly, it's always nice to-- Travis is really nice, but it's always nice to minimize the number of tools, if you can, so that you don't have to keep track of a separate service. COLTON OGDEN: Andre's got a question for you as well. KAREEM ZIDANE: So let's think that one. "Hi, Kareem. Hi, Colton. Sorry, I'm a bit late, so do ignore the question if you've already addressed this-- but really stupid question." There's no such thing. "Where does the build's automated tests of a Travis CI actually happen? Is it server side?" That's a great question. All of these builds do happen server side on Travis's computers or on Travis's infrastructure servers. So they are completely hosted for us. We don't have to worry about that. We have-- do we have a second question? COLTON OGDEN: Yeah, GeekNabil. KAREEM ZIDANE: "I joined the stream give minutes ago, and I noticed Kareem wrote a prime function, and tested it locally, and the test succeeded. The question is, why would we push the code on Travis server? What are the advantages that we get from that way?" So we I think we answered a very similar question. It's still a good question though. And we mentioned that the idea of having these tests also run on Travis is that the Travis environment is the same for everyone. So if Colton is working on the same repository, if he pushes some changes, then the tests are still run on Travis CI, even if Colton did not run any of these tests locally first. So this is just to ensure or enforce that these tests are run before we merge them into our master branch. COLTON OGDEN: PresidentOfMars-- thanks for joining us-- says, "Are there notes that go specifically with the stream? Also, you could create a command Foo with Twitch chat with all the info to not repeat it all. Just put it in the title, wink." So there are no notes formally that go with the stream. We do have a GitHub repository that Kareem is writing to. So it's GitHub.com/KZidane/CICDStream. KAREEM ZIDANE: We can actually post that maybe here. COLTON OGDEN: Yeah, if you want to write that in the chat. And so we-- generally, for these kinds of streams, because they're more free-form, they don't adhere necessarily to a set of notes or slides, we don't have accompanying slides or notes. But the GitHub repositories that we usually have associated with it will more or less cover the flow of what we've done and have all the accompanying material. So you can follow along that way at least. And then for more structured presentations, going in the future we might have more of a formal sort of slide setup, but as of now, we don't have anything of that type. And as for the Twitch chat command, if you could elaborate on that, because I'm not quite sure I understand what you mean by that. But thanks for the question. Then JefferyHughes also plugged in the stream, so thank you. KAREEM ZIDANE: Sounds great. So the next thing that we should probably go through-- so before the stream, the lazy part of me thought write a simple web page, simple HTML page, and deploy to GitHub Pages, but the developer part of me said, you should probably do something cool. And so for the next part we're going to use a service called GitHub Pages provide by GitHub, and GitHub Pages is simply a hosting service. It's a service that allows us to host static websites. COLTON OGDEN: And it's free for public repos, right? KAREEM ZIDANE: It is free for public and private repos, I think. And what I mean by static websites is that, if you have a bunch of HTMLs, ESS, JavaScript, other assets like images, audio files, video files, and so on, you should be able to host your static website on GitHub Pages pretty easily, literally, just like pushing your code. COLTON OGDEN: PresidentOfMars, "Command automatically posts all links to your group/GitHub." That's a good point. I'll start putting that in the description. I think I put that in the description for a couple of videos. For the videos I put on YouTube, we definitely do that, but on Twitch I think only just the first couple-- oh, a Twitch bot that actually does it. Oh, OK, that's a good point. Yeah, Twitch does have bots that you can program, which in itself would be an interesting stream, a stream on programming a Twitch bot. Maybe we'll do that live sometime. That's a cool idea, so yeah, thanks for the suggestion, PresidentOfMars and LincePutalWire. KAREEM ZIDANE: So if you've-- a really cool static website that I'm going to use right now is the sample code that Brian used for his stream on React, which is, by the way, a great stream. So do give that a look if you're interested in React. Brian is a great teacher. And if you don't recall, it was a single file, game.HTML, that had a very simple game. So let's actually open this in Google Chrome. And it's a game that essentially-- let me zoom this in a little bit-- gives you a bunch of addition problems, and you're supposed to write the correct answer, hit Enter, and so on. It gives you a different problem if you write something wrong. It gives you-- it switched the problem to red. COLTON OGDEN: I like how we sort of build on that last stream and we're going-- or a couple of streams ago-- and now we're using it in another context. That's a cool idea. KAREEM ZIDANE: Yeah, I really enjoyed that stream, because I knew something about Angular, I knew something about Vue, but I really didn't know anything about React aside from the fact that it's pretty similar to both of these two. COLTON OGDEN: It's very elegant. KAREEM ZIDANE: Yeah, Brian did a great interaction to that. So I highly recommend watching it if you haven't already. So the cool thing about this is, one, we can deploy a static website like this to GitHub Pages, have had it hosted online. Two, we can also do a bunch of tests on it. What do you prefer? Do you prefer testing first or deploying first? COLTON OGDEN: Probably testing, I would say. KAREEM ZIDANE: So the testing code for this is a little bit more complicated than the testing code from before. Again, this is not really-- we're not really going to go into deep details about the code here, but I wrote this in advance. And let me show you what it does after commenting these out first. So I'm importing a bunch of stuff here. I'm using a tool or a library called Selenium, which is a very popular tool for testing the front end of our applications, in this case. So I'm importing a bunch of stuff from Selenium. And I have a helper function here that takes a file name and returns a URL for it, file:///something, if you've noticed the thing in the top here. So this function is essentially going to say game.HTML and return something like this so that I'm able to open the file in my browser. And similar to the structure of the previous test.py, we have a class, in this case called "game tests," that extends unit test case, unit to a test case, so very similar. We have helper problem functions that we look at later. Let's actually start by these test functions. So the first thing we have a function called test_title. And can you try to guess what this does just by reading through the code? COLTON OGDEN: So it looks like it says-- it's asserting equal, self.assert equal. So earlier we looked at assert false, which means make sure that this is equal to false, and it'll return whether it's equal to false or not. KAREEM ZIDANE: Right. COLTON OGDEN: So driver.title is basically-- I'm assuming that that's the title of the-- I don't know if it would be the title of the tab, or the title of the web page, or the tab, one of the two. KAREEM ZIDANE: Yeah, it's pretty much the same, yes. COLTON OGDEN: And then just make sure that it equals Hello, the string Hello. KAREEM ZIDANE: Exactly, so if you've noticed actually earlier when we opened this in the browser, the title of the tab here, as you mentioned, is Hello. So we're doing exactly that. We're checking that the title of the tab is Hello, in this case. What about the next one? Do you have an idea? COLTON OGDEN: So on 9/11? KAREEM ZIDANE: Yes. COLTON OGDEN: So it's a function called Test Input Cleared After Correct. So I'm guessing, because in Brian's stream, if he got the answer correct, the text would clear. KAREEM ZIDANE: Correct, that's exactly right. COLTON OGDEN: So we have a variable called _Input, which is equal to self.solveproblemindex2, which I'm not entirely sure what that is. I'm guessing that that's a DOM element. KAREEM ZIDANE: So we're solving the problem. Yes, we are getting a DOM element. We're getting the input text field, in particular, in this case. COLTON OGDEN: And then we're doing the same thing we did earlier, where we're saying self.assertequals. So is it equal that the value attribute of that DOM element-- so whatever its actual literal value is that we can see in the page-- is equal to the empty stream? KAREEM ZIDANE: That's exactly right. Let me actually demonstrate this. So as we mentioned, if we get the answer right, we hit Enter, the text field is cleared afterwards. COLTON OGDEN: Nice. KAREEM ZIDANE: So we're exactly testing for that. We are solving a problem correctly, presumably, and then hitting Enter, and then we're checking the value of the input field to make sure that it's clear. COLTON OGDEN: And this is sort of how you do the front end development. You are actually picking apart pieces from the DOM, from the web page, and it's like comparing the values at one given instance of time. KAREEM ZIDANE: Correct. Last one we have here is test_ red_after_incorrect. We'll test right after incorrect. And I try to be descriptive in my function names. You might notice these are a bit long, but I think that's mostly OK for testing functions so that you have an idea. But I think you could also, if you looked more into unit test, you could also provide a more detailed description of your testing functions as dark strings. This unit test is probably for another stream, so we're not really going to dive into this much, excuse me. And in this case, we're also solving a problem incorrectly, presumably, as indicated by this correctly equals false argument. And then checking that the color of the problem element, which is a div, is RGBA255001, which means it's red and fully visible 100% opacity or transparency. COLTON OGDEN: JefferyHughes asks, "Is CS50 hiring?" I'm guessing that's what you're asking. Not actively, no. And generally, when we do hire, to the best of my knowledge, we post it on our CS50 Facebook page if it's something that we're seeking candidates for outside of sort of the people that we know privately and within Harvard. So definitely-- or even if you are part of Harvard University. Pay attention to our CS50 Facebook group for more info on that, if we do hire more folks in the future. Thanks for the question. KAREEM ZIDANE: Cool. So again, let me demonstrate this one last time. If I enter the answer wrong and I hit Enter, the color of the problem should turn red. So this is what this is testing for. COLTON OGDEN: And so Selenium, I'm guessing, is giving you this function that's a value of CSS property? KAREEM ZIDANE: Correct, yes. So problem is the DOM element. Let's actually look at this whole problem. And this is the helper function that I wrote that literally does this. It solves a problem correctly or not, based on what you pass here as the value of the correctly parameter. And it, first, finds the element whose ID is problem. It then tries to solve the problem, solve the addition problem. If you're not familiar with this, maybe you look at the documentation for funtools.reduce. But if you're going to trust me on this, this solves the problem correctly, assuming you didn't do any mistakes. It then gets the input element by its tag name, and then sends a bunch of keys to that text input. So either enters the correct solution of the problem or something else, which is presumably incorrect. Then hits return, and then returns the three things that we care about, which is the problem element, the input element, and the result, which is the correct result in this case. COLTON OGDEN: This is cool, a nice little simple function to solve the problem. KAREEM ZIDANE: Yeah, you might even start by duplicating all of this logic in your functions, but it's nice if you can factor something out. There's also a function that we didn't talk about so much, called "setup," and this is also a special function in unit test of test case that is run before every test is run. So in this case, what I want to do before every test is actually open the file game.HTML in my browser. It's actually cool if we demonstrated this live. So let's try to run Pythontest.py as we did before, and of course, there's no modules called Selenium, because we're-- COLTON OGDEN: And because previously you had that Selenium virtual environment setup. So this is, I'm assuming-- KAREEM ZIDANE: Exactly, yes. So I deactivated my Selenium environment. So to install Selenium, you're going to have to do PIP install Selenium like this if you don't have an installed already. You're also going to need something called Chrome Web Driver. So if you Google "Chrome,"-- COLTON OGDEN: If you're using Chrome. KAREEM ZIDANE: If you're using Chrome. But you could also-- the good thing about Selenium is that it doesn't care much about the browser. There are a bunch of supported browsers. Firefox, I believe, is one of them, so there are drivers for different browsers that you could use with Selenium. So you should download this if you don't have it, and install it on path. So in my case, I put it in user local bin Chrome driver, in this case. So let me actually-- I have this already all set up in my Selenium environment. So let me activate this and try again. And the test failed-- "Driver is not defined." This didn't happen before. [LAUGHTER] KAREEM ZIDANE: So let's see. "Named driver is not defined." Let's see. COLTON OGDEN: Oh, because you commented the code out. KAREEM ZIDANE: Yeah, I commented one of the things out. So let's try to fix this. Oh, I commented this line and I shouldn't have. So in this case, just to initialize Selenium or the web driver for Chrome. In this case, I just do web driver-- which we imported up here from Selenium-- .Chrome, literally. Try this again-- fingers crossed. And it opens a browser automatically. It does a bunch of stuff really, really fast. COLTON OGDEN: Nice. KAREEM ZIDANE: And then if we look back at the terminal we should see that all has succeed, because, presumably, we didn't break anything. So let's look again at the code and try to break something. COLTON OGDEN: It's probably a very satisfying thing to watch for a very large set of test cases. KAREEM ZIDANE: Yeah, exactly. We're going to change this in a bit, but this is really an amazing thing to watch when you see the computer doing things automatically in the browser tab. COLTON OGDEN: It's a good way to test Chrome's speed as well. KAREEM ZIDANE: Yes, true, in a sense. So I commented out this line here, which clears the input field after a correct response. So I'm just breaking it intentionally, so let's see what happens here if I run the tests again. A bunch of crazy things happen again. And then if I check-- hmm. It's telling me that it expected the value of the input field to be empty, but it found two in it. So that means that the input field wasn't cleared. So in this case, the test failed. So one question that might come to your mind is, how is this going to work Travis at all? How is Travis going to be able to launch a graphical web browser and run a bunch of tests in it? And the answer is, it doesn't. Because there is a feature of Chrome and other browsers as well that allows these browsers to be run in the so-called "headless mode," which is a mode without actually a graphical user interface. So you can have a browser without actually a graphical user interface, and that's what we're going to use in this case. So let me comment these in, I guess, again. Whoops-- not delete them. So in this case, I just added the headless option to Chrome options. I created Chrome options up here from web driver, the Chrome options by instantiating webdriver.chromeoptions. I added the headless argument and then I instantiated the driver the same way, except that I passed options this time. So let's try this again. It still, presumably, runs the test in Chrome, but we don't see a crazy thing happen using GUI. And this is what we're going to use in an environment like Travis to test our project. Any questions? Let me actually fix the bug that I made. COLTON OGDEN: Yeah, the React bug's still there. KAREEM ZIDANE: You know what? Let's actually push this way and see how it's going to fail. So let's actually take a look at Travis.yaml, And it's pretty similar in this case. We are using the same language, Python in this case, because our tests are in Python. Although, technically they don't have to be in this case. I think Selenium also supports a bunch of other languages, excuse me. So this is a new thing. "Sudo: required" means I don't want to run my tests in a container. I want to run my test in a fully fledged machine, a virtual machine. And the reason I have this is because I want to use sudo, and Travis, unfortunately, doesn't allow you to use sudo instead of container, so I have to use a virtual machine. So it's going to be a little bit slower, but it's going to give us the feature that we care about. It turns out I don't have to install Chrome on Travis, because it allows us to enable Chrome simply by passing add-ons and then as a child key of it or however you want to call it. Chrome:stable-- I also know this by checking the Travis documentation. A step that we haven't seen before is the before install step. So we saw the install step. The install step usually is used, although nothing forces you to do that. Usually, you used to install your package with all its dependencies. In this case, I'm using before install. Or I usually use before install to install any-- maybe build dependencies, or any testing dependencies, in this case. So I'm installing Chrome driver, because I don't think it's installed by default on Travis. I'm installing it in the same location, user local bin, and then I'm removing the zip file that I downloaded. I'm also installing Selenium. So this is how you can run more than one command in one step like, script, or install, or before install, in this case, by adding this little dash before the command-- before every command, actually. So this creates a list of commands. So I'm first installing Chrome driver, as we mentioned, and then I'm simply running PIP install Selenium. COLTON OGDEN: So this is little bit more complicated and custom-tailored than doing a requirements.txt that you would use PIP to install? KAREEM ZIDANE: Correct. But in this case, I believe requirements.txt is usually used to install or list the dependencies of your project. In this case, I'm not sure. People could argue with that. I don't think Selenium is a dependency of my project. My project doesn't need Selenium to run, but I do need Selenium to test. So that's kind of separate. COLTON OGDEN: That makes sense. KAREEM ZIDANE: So what I'm going to do now is git status. All these changed. Let me add everything, and let you git push to master. Of course, I forgot to git commit again-- broke tests, push. And if I go back to my browser by closing all of these, my repository is called KZidane/reactsaddition, I believe. Yep, there you go. Go to Build History. You're going to find that there's a new build here, click it. It's also still taking a little bit of time to start. And this is actually probably going to take a little bit longer, because it's more heavyweight than the container itself. There's not much really that we can do while waiting for this. COLTON OGDEN: That's the unfortunate part about it. KAREEM ZIDANE: Yeah, we can look at the Travis documentation while this build is running. So you can have, among a Travis feature, you can have a bunch of jobs that are running simultaneously if you care about this. So if you have a bunch of tests that you want to run side by side, so to speak, or in parallel, at the same time, you can do that using the jobs feature of Travis. Travis also explains a bunch of-- how to install your dependencies for your project. So do definitely check the configuration for how to do this, if you're curious. The programming languages that Travis supports-- so we happen to use Python in this case-- but here is a list of all the languages that Travis supports. COLTON OGDEN: Quite a good set, actually. KAREEM ZIDANE: Yeah. COLTON OGDEN: Even Pearl. KAREEM ZIDANE: Yeah, so there is Pearl, there is Swift, there is-- I don't know who codes in Visual Basic now, but there is Visual Basic. COLTON OGDEN: Who codes in Pearl? That's what I want to know. KAREEM ZIDANE: There are a bunch of scripts in Pearl right now. Anyway, not our problem. Deployment options, we're going to look at deployment shortly. Here's how to deal with environment variables, documentation about that as well. Here's how to encrypt data. So if you have passwords or security tokens, you can actually encrypt these using Travis or have Travis encrypt them for use so they're not publicly accessible by everyone. We talked about using an environment variable for this, but there are other options that Travis gives you in this case. Also, one of the cool features of Travis that we do use is the notification feature. So you could have Travis actually send you an email once the build succeeds or fails, or send the message to Slack, if you're using Slack, or a bunch of other things. So this is what notifications on a higher level are used for. I believe this is for developing Travis itself, if you're curious. By the way, Travis is open source on GitHub as well. So if you go to GitHub.com/TravisCI you can see a bunch of their repositories. And this is probably Travis for enterprise, if you have a big company and you care about this. COLTON OGDEN: Make and host your own version of Travis. KAREEM ZIDANE: Exactly. So if you go back to our build here, it's obviously broken, and let's try to figure out why. And if you scroll down, down, down it's telling us pretty much the same thing. So it's ran the same tests that we ran locally using a headless browser, in this case, and it's telling us that it found two in the input field, but it actually expected an empty string. So let's actually fix this and try again. So if you go back to game.HTML-- whoops. Sorry, Brian, for breaking your code. COLTON OGDEN: It's for educational purposes. KAREEM ZIDANE: Save, add game.HTML, commit fixed again, push, and it's going to take a minute or two to finish starting and building. Let's click on this just to get it ready. Now, how do we deploy our website to GitHub Pager? And the nice thing about Travis is that it actually has a so-called provider that's built-in that allows you to do this pretty easily. And so let's actually google this. Let's do "GitHub Pages Travis CI," and first thing that appears here is GitHub Pages Deployment. And it seems to be the case that I need this block of code. If you read through, you'll figure this out as well. So it seems to be the case that I need this block of code in my Travis.YAML. So I'm just going to do exactly that. Copy that, go to Travis.YAML, paste this here, and then just go through these one more time. So hmm, here's an interesting thing. So the skip clean up key value pair actually, in this case, happens to be useful only when you have certain build artifacts. So if your program or your app is built into a static website, this will be useful. It's not really useful in this case. By default, after the script step, Travis actually clears any changes in the repository or stashes them, if you remember git stash from the last stream. So we don't really care about this right now. We can get rid of it. GitHub token is the token that Travis is going to be using to make a push to your repository on GitHub, because this is what we need in order to have GitHub Pages working. COLTON OGDEN: For the authentication. KAREEM ZIDANE: Correct. I don't really care about keep history. I'm going to delete this comment, because it's not really useful in my case. I can infer this. By default, I think, this is going to happen only on the master branch, and this is what onbranch:master tells us. So you can imagine changing this. You can imagine working on a development branch, and then only when you merge or push your code to your master branch, that this deployment is actually going to happen to production. But more importantly, this deployment is only going to happen if the script step succeeds, so if our tests all pass in this case, which is a good thing. So we seem to need a GitHub token, and I forgot about this before the stream. So I'm going to go to my GitHub.com. COLTON OGDEN: Do you me to turn your-- KAREEM ZIDANE: Let's actually show first where to generate a token first. COLTON OGDEN: Here, so take the chat off so that we you can see where. KAREEM ZIDANE: So I clicked on my profile picture here up on the top right. I chose Settings, and then I believe it's under Developer Settings, and then Personal Access Tokens. So you can actually generate personal access tokens using this view right here. So if you can switch my screen right now, I'm going to create my token. Let's call mine "react," and then I'm going to give it the repo scope, generate token, copy this token. And then can you switch back my screen? COLTON OGDEN: Yeah. KAREEM ZIDANE: Thank you. So I generated a token and copied it-- actually, we're going to have to go away one more time, but not now. COLTON OGDEN: Oh, aren't you going to-- you have to paste it into your file, don't you? KAREEM ZIDANE: Sure. So let me actually do this. So GitHub token, paste it here, add. COLTON OGDEN: So you can show the fields that you entered it into, if you want. KAREEM ZIDANE: Sure. So here's my previous view. Here is the build that we just ran after fixing. Everything passed and everything is as expected. So for this, we're going to use an environment variable, and to add an environment variable, I'm going to do More Options, Settings, and then go down to Environment Variables, and then add a variable here. In this case, we seem to be using a variable called GITHUB_TOKEN, all caps. This is not including the dollar sign. The dollar signs is used to refer to this variable in the shell after assigning it. So what I did was that-- GitHub token, token, and then pasted the token here, and then hit Add. COLTON OGDEN: And that's what we see right above there, where you have environment variables set. KAREEM ZIDANE: Exactly. You need to make sure, in case of secret credentials like these, we need to make sure that the display value in build log option is off, because otherwise you can actually see your GitHub token and build log. Everyone can see it, which is worse. Also, an important feature of Travis is that it actually allows you to-- once you set the environment variable, you can't change its value. So no one, even me, including me, can actually see what the value is in here. All I can do to it is actually delete it if I want. COLTON OGDEN: MajorDefad says, "Stupid question. What does it mean to deploy a website?" KAREEM ZIDANE: That's a great question, actually. What it means to deploy a website is to publish it somewhere, for example. So if your website-- in this case, we're going to publish our website on GitHub Pages, so host it somewhere, be able to reach out to it using the internet. But yes, the term "deploy" actually was very confusing to me at first. All this means is actually publish our website somewhere. COLTON OGDEN: Take it from your local machine to some server where anybody can reach. KAREEM ZIDANE: Correct. But interestingly, it can actually mean something else in different contexts. So if I'm deploying a Python package, for example, you might think of that as publishing this on some package index, like PiPy pi, or maybe creating a release in GitHub or something like that. Good question. So now that I have this set, there is one more thing that I need to do. First of all, I'm going to go to my repository in GitHub, so re:KZidane/reacctaddition, and I'm going to do Settings, and I'm going to scroll down a little bit to GitHub Pages. I'm going to select my default branch, which is master, in this case, and this is the branch that I want GitHub Pages to consider. If I push to master branch what I'm going to do, what GitHub is going to do, is actually serve my website somewhere. So let's choose this. Let's hit Save, and then let's actually, now that this is done, let's actually do another push after we add the deployment stuff. Git status, it's changed, Travis CI, commit, and then enabled GitHub Pages, git push. So now this is going to take a second or two. COLTON OGDEN: And once it finishes verifying that the build succeeded, it's going to take that deploy the key and follow with the instructions that you specified for it, the token and put that on the internet somewhere. KAREEM ZIDANE: That's exactly right. So let's actually follow the build log here, and let's wait for this to start. this is going to take a while. We're waiting for this, once you enable GitHub Pager on GitHub from the repository settings, as we showed, this is the URL that you could use to reach out to your website. COLTON OGDEN: It gives you your username.GetHub.io normally, slash, and then the name of your repo. KAREEM ZIDANE: Correct, but you can also specify a separate custom domain if you have this already. If you have your own domain, you could just set this up if you want to. So hopefully, now that our tests pass, it's going to go through the deployment step. Notice, the build is still running after passing the tests. And now it's installing deployment dependencies, a bunch of Travis-related stuff, cloning the repository it seems, and then deploying it. And exited with zero, which is correct. COLTON OGDEN: Nice. KAREEM ZIDANE: So now, hopefully if you go to this, /games, because our file's called games. Or is a game? It's just game, so game.HTML. Hopefully we should see our game online. COLTON OGDEN: Nice. Live on the internet for everybody to see. KAREEM ZIDANE: So that's everything I have have for today. COLTON OGDEN: The Jasong or the Yasong says, "Hello." Hello, Jasong or Yasong. KAREEM ZIDANE: Hi. COLTON OGDEN: I'm not sure if that's a German J, or an English J, or some other J. KAREEM ZIDANE: Do you mind switching to my screen? COLTON OGDEN: Oh, yeah. Oh, sorry, did I-- KAREEM ZIDANE: That's OK. I'm just going to quickly get rid of this token, because we don't need it anymore. COLTON OGDEN: "It's putting it online?" Yes, website is now online. Greece, ah-- I'm not sure how the J is pronounced in Greece, actually, but hello to you from Greece. Thank you for joining us. That's quite far away. KAREEM ZIDANE: Yeah, thank you. COLTON OGDEN: So that's it for today's topic, you said? KAREEM ZIDANE: Yep. That's all I have for today. We can maybe take any questions if you have any. COLTON OGDEN: Sure, yeah. We'll stick around for a few questions. So we talked about CICD, so unit testing, deploying with Travis. So starting from the bottom, going all the way up to fully deploying an app and testing it along the way. So yeah, we-- oh, can they play it? Buddia2610. KAREEM ZIDANE: You can, yeah, definitely. Just go to-- COLTON OGDEN: What's the URL? KAREEM ZIDANE: KZidane.GitHub.io/react-addition/-- COLTON OGDEN: KZidane/GitHub-- it's not the shortest URL-- slash-- KAREEM ZIDANE: That's why you should configure your custom domain. /react-addition/game.HTML. So, yes, you should be able to access this now on the internet. COLTON OGDEN: Wow, look at that. That's so cool. We put a website online live on CS50 TV. CoralSase says hi from Italy. Hi from US. Thanks for joining us all the way from Italy. Wow, we have such an international audience. It's amazing. KAREEM ZIDANE: Yeah, that's amazing. COLTON OGDEN: I'm guessing it's evening over there, right? What's evening, is it [NON-ENGLISH SPEECH]?? No, that's Spanish, I think. How do you say good evening? KAREEM ZIDANE: It's 8:31 PM, Colton. COLTON OGDEN: How do you say good evening in Italian? I forgot. Let's figure this out. KAREEM ZIDANE: I have no idea. COLTON OGDEN: Well, we'll do it live. Good evening is [NON-ENGLISH SPEECH]. I was close. [NON-ENGLISH SPEECH] I think I said [NON-ENGLISH SPEECH],, which I think it means good luck, and [NON-ENGLISH SPEECH] was good luck in Spanish. [NON-ENGLISH SPEECH] KAREEM ZIDANE: Yep. COLTON OGDEN: 8:30 is not too late, but it's a nice comfortable time to watch some Travis CI streaming with Kareem Zidane, CS50's Kareem Zidane. It looks like the white on your Chrome fades down to a slightly dark color. You can see it on the stream, it's like an off-white. Or is it because you Flux-enabled or something? KAREEM ZIDANE: I'm not sure what you're referring to. COLTON OGDEN: Your screen goes yellow over the course of the day. Does that happen? KAREEM ZIDANE: Not really. I don't think so. COLTON OGDEN: Kalinicta in Greece. Oh, nice. I'm not sure where that is. Kalinicta. I'm not spelling it correctly-- kalinicta. It's bringing up the actual Greeks, which is a little bit-- or the Greek, which is a little bit trickier. Why is it not bringing it up? Here, let's bring up the actual Greek. Oh, that's how you say good evening. Oh, I see. Good night, kalinicta, yeah. Yeah, [NON-ENGLISH SPEECH] is fate in Spanish. Ah, yes-- good fate, good luck. [NON-ENGLISH SPEECH] KAREEM ZIDANE: Cool. COLTON OGDEN: [NON-ENGLISH SPEECH]. KAREEM ZIDANE: You do get a language tutorial as well, not just-- COLTON OGDEN: Yeah, little bit. A very, very poor language tutorial on CS50's live stream. Question. "Why do most programmers go for a Mac instead of a laptop using a Linux distribution?" What's your opinion on that? KAREEM ZIDANE: I personally use Linux, Ubuntu specifically. I feel like I'm much more comfortable with that, much more productive with that. I haven't tried and Mac too much, so I can't really say a useful opinion on this, but maybe you could give us an insight. COLTON OGDEN: Well, they're similar enough, because a lot of the same programs and shell commands are identical. They do have some differences, obviously. Package managers are going to be different. It's apt-get for Ubuntu, right? KAREEM ZIDANE: That's true. COLTON OGDEN: Mac doesn't really have it built-in. KAREEM ZIDANE: Snap right now as well. COLTON OGDEN: Which one? KAREEM ZIDANE: There's Snap as well. Snap on Ubuntu. But to me, honestly, Ubuntu comes with a whole bunch of stuff in the preinstall that makes certain things easier for me, which is good. Also, the fact that-- and I'm saying this honestly-- I struggle sometimes to do something, but I also learn a bit more using Linux. COLTON OGDEN: Yeah. No, it's definitely much more-- it's closer to the actual kernel, I guess, or closer to the-- I guess your file. You're not abstracted as much away using graphical user interfaces. You're looking at all your files as they actually are. KAREEM ZIDANE: Yeah, that's true. At some point, yeah. COLTON OGDEN: And you're interacting with things that normally-- environment variables aren't something that a user typically interacts with. KAREEM ZIDANE: Yeah, these exist in Mac and Windows as well, but they're not-- COLTON OGDEN: But you're more forced into-- KAREEM ZIDANE: If you're a normal Windows user, you probably wouldn't hear about these. COLTON OGDEN: You do occasionally. Windows development is a little bit-- it feels messy, but at least they have the-- what is it-- Linux bash Subsystem or something like that. KAREEM ZIDANE: I haven't tried that one as well, but I've heard mixed opinions on it. COLTON OGDEN: "I'm on Ubuntu too, but thinking to go to Mac." I don't know if there is necessarily a super-- Mac is just a great user interface. And that's their selling point, is their operating system is just nice to use. But I honestly don't-- if you're comfortable on Ubuntu, I can't necessarily recommend either way. I think just go with whatever system. I'd say try a Mac and see if you like it. Try a PC. Try everything just to get a sense of what the landscape looks like just to determine whether or not you find a particular operating system enjoyable to use or not. Let's see what we have. Jeffrey says, "It's been seven years now under Windows Linux and used a VM for Mac, and I think to switch to a real Mac." Yeah. No, Macs are really-- they have a lot of cool features and just a lot of their services work really well together, but it's not mandatory. You can get by using whatever machine you're comfortable with. "Windows has PowerShell, i.e. a better shell for Windows." Yeah, you can use Windows PowerShell instead of the command prompt to do some more stuff. And you can also install git bash, and a node shell, and all kinds of other stuff. KAREEM ZIDANE: I do believe that Travis CI also supports an OS X environment if your application works only on OS X or you would like to test your application also on OS X. I don't think I mentioned that, but by default, I believe it uses some distribution, some version of Ubuntu as well, maybe 16.04 or something. COLTON OGDEN: That makes sense. I'm guessing probably because most web applications typically assume that they're running on a Linux server as opposed to a Mac. KAREEM ZIDANE: Yeah, I believe they have both options, but you can have a bunch of other things as well here. Cool. COLTON OGDEN: It seems like a very flexible platform. KAREEM ZIDANE: It is. It definitely made a lot of things easier for us. It made us focus more on development rather than worrying about the details of how to deploy your app. Because, you can imagine, deploying your app, if it's more complicated than GitHub Pages, a static website, can be really complicated and can require a lot more time and a lot more effort to do, which would make it mistake-prone or error-prone. So you sometimes find yourself messing things up. But right now, you literally have a computer doing this for you, and it's doing the exact same thing every time. So there's no reason-- there should be no reason why this should fail. COLTON OGDEN: Yeah, I agree. Joseline says, "You're awesome, guys." Thanks, Joseline, thanks for coming in. KAREEM ZIDANE: Thank you so much. COLTON OGDEN: CoralSase says, "I have a suggestion for the game programming streams. You could do a game with basic networking, maybe using LuaSockets, something like a multiplayer snake or some basic thing like that." Yeah, that's a good idea. I'll take a look at it. I'd have to read up on LuaSockets and probably tinker around with it a bit before diving in blind, but I could maybe put together something simple and try to implement it live. Buddia2610, "There is PowerShell for Linux." Interesting. I'm not too familiar with that. Maybe you have some knowledge about that, if you want to read that last question. KAREEM ZIDANE: Sure. "Kareem, when does it make sense to use unit tests or E2E tests? New programmers add tests just like that, even if it's unnecessary." I'm not familiar with E2E tests, so I'm just going to Google this on the fly and see if I might be familiar with it. I don't know. Are you familiar with that? COLTON OGDEN: I'm not sure. I thought E2E was end-to-end testing. KAREEM ZIDANE: Yeah, I'm probably going to have to read more on that. COLTON OGDEN: It's, I'm guessing, testing for-- I think the scenario is like testing the whole flow of using an application, from the beginning of a user logging in and doing all the features of your application, until the last logging out of your application. KAREEM ZIDANE: Does that also mean you could use your tests for something like that? Because it seems like you could implement a whole flow using unit tests as well. COLTON OGDEN: Yeah. You would have all the sub things as unit tests, and then an end-to-end testing would be the entire application from a user's point of view, like using it like a normal user would basically. Basically, it'd be a sequence of unit tests in a particular order, I think. KAREEM ZIDANE: Forgive me for my ignorance on this subject, but if I understand this correctly, it seems like you could use unit tests, but also perform or use end-to-end tests. If the idea is, should you write test cases that are not necessary? Probably, no. But some people-- writing tests is not really a fun thing to do. It's not an easy thing to do, and it can take a lot of time. So what a lot of people I know do is actually write tests as necessary. When we figure out a bug, we demonstrate it. We actually do pinpoint this bug with a test case, and then eventually you're going to have a bunch of test cases that cover most, if not all, of the problems in your code. I know there are also some tools, called test coverage tools, that potentially point you to certain parts of your application that you didn't cover in terms of testing. So maybe you could give that a look and maybe try to use them. But I would say, especially if you-- you should probably-- yeah. You should probably write only the necessary test cases in this case. Don't try to overwhelm yourself by trying to write a whole bunch of tests before even starting to code. Some people say that's a good practice, but it can discourage you, I would say. COLTON OGDEN: It'sDelusional says, "So what does this fall under?" KAREEM ZIDANE: I'm not sure. What, are you referring to end-to-end? COLTON OGDEN: I think he's referring to-- I think he's just asking, what do we do today? Probably just unit testing is what we covered today. KAREEM ZIDANE: Yeah. Well, we didn't cover unit testing in details. We did cover continuous integration and continuous deployment, and we also talked a little bit about unit testing as well, and testing using Selenium, which is pretty useful. COLTON OGDEN: Nice. Well, we'll see if anybody has any last questions. I'll bring us back to the middle title card there. But yeah, it was a good stream. So thanks for coming on again and giving us a part two of the GitHub and now we did the Travis stuff. We'll have to have you on for an actual programming stream sometime. KAREEM ZIDANE: Yeah, hopefully. Yeah, thanks so much for having me. Thanks, everyone, for joining today. I hope that was useful. COLTON OGDEN: Yeah, it was really well-done. KAREEM ZIDANE: Thank you. COLTON OGDEN: So tomorrow we have Dan Coffey on the stream, CS50's head producer. He helped set up this whole room, so shout outs to Dan Coffey. He'll be talking to us about the draw50 app that David uses in lecture to simulate a digital blackboard and how that works. It's actually a JavaScript application that we use on a giant-- I think a giant Microsoft Surface TV. Then on Wednesday, it'll be just me. We'll do tic-tac-toe in Lua and Love2d, so back to 2D from last stream. Last Friday we did a unity stream in 3D, so we're going to go back to 2D. A very simple game, tic-tac-toe, which will be a lot of fun. And then on Friday, Nick Wong, who did the stream last week, will be back, and he'll be giving us a tutorial on Linux commands. So if anything that we've done today or in the past with the command line has been a little bit difficult to parse or maybe a little foggy, and you want more hands-on breakdown of what's going on at the command line, some basic commands and a tutorial, then Nick will give us a basic tutorial then. And then the week after, we've got some more stuff. We have Veronica Nutting, CS50's head course assistant, will be giving us a Python tutorial. So 100 cool things to do in Python. KAREEM ZIDANE: That's great. COLTON OGDEN: Depending on how much time we have, we may not be able to cover all 100, but we'll try our best. So yeah, and so we have a lot of stuff lined up. BasedAvon says hi. Hi, BasedAvon. Nice to having you in today. It'sDelusional says, "Are you related to Zinedine Zidane?" KAREEM ZIDANE: I wish. I'm a big fan of Zinadine Zidane. It's just a coincidence that our last names are the same. But yeah, he's definitely a fantastic player and I'm a big fan of him. COLTON OGDEN: MajorDefad, "Thanks, Kareem and Colton, this has been useful." Thanks for coming in today and being a part of the stream. Glad to have you today. M. Kloppenburg, thanks for coming in. "Thanks, Kareem and Colton." Lince, thank you. Jasong says bye. Thanks, Jasong. Thanks for coming in. Belecure, "Thanks, Kareem and Colton. This is very useful, as usual." Thank you so much, very much appreciate it. BasedAvon, "What about deploying to another site or place other than in this video?" KAREEM ZIDANE: That's great. Can you actually switch my computer on last time? So if you go to Travis deployment provider, we search for that, you would find that Travis actually supports a whole bunch of deployment providers. So we happen to be using GitHub Pages in this stream-- let me zoom this in a little bit-- but you can also deploy to Heroku somewhere here. Let's see. Yep, there you go. So you can also deploy to Heroku. You can also deploy to AWS, Elastic Beanstalk, cloud storage, package clouds, a bunch of other services. And even if none of these fits your use case, you could also have a custom deployment script that does whatever you want. COLTON OGDEN: There is a massive number of services there. KAREEM ZIDANE: Yeah. COLTON OGDEN: LincePutaWire, "Who is the cat in the profile picture?" If you're referring to the CS50 Facebook group, then that's the Happy Cat or I Can Has Cheezburger?, which is a very famous meme cat that CS50 has adopted for a lot of its iconography. So definitely Google that, check that out, see the history behind it. Andre says, "Kareem did an awesome game for his CS50 final project way back when. Perhaps you could persuade him to revisit this, Colton." KAREEM ZIDANE: Thank you so much. I don't really think of it as an awesome game. COLTON OGDEN: What was the game that you did? KAREEM ZIDANE: I think it was some version of checkers. It did use the Stanford Portable Library. I don't even think I have the code for that anymore. COLTON OGDEN: We can maybe pull it up or maybe implement a version of it live on camera sometime. KAREEM ZIDANE: Sure. You're the gaming developer, so you should probably-- COLTON OGDEN: Well, we can maybe have you-- we'll have you as a guest for that one. We'll have you talk through your-- KAREEM ZIDANE: I did watching your Unity stream, by the way. I didn't know anything about Unity until I watched your stream, and it wasn't amazing. COLTON OGDEN: Yeah, Unity is super awesome tool. I'm super excited to do some more streams in that. It's an awesome tool. KAREEM ZIDANE: It was nice to get a basic idea of how all of this fits together and how it works. And it's really simpler than I thought. COLTON OGDEN: Yeah, it's very easy. It gets very complicated the farther you dig into it, obviously, but just to get started with it, super nice and super easy. KAREEM ZIDANE: That's great. We have-- It'sDelusional says, "Thank you, guys." Thank you. "I use Python and another languages for benchmarking and found out, as a whip div, that Python nowadays is falling back and is slower than other languages. I read that it's the most used language in AI and machine learning. My question is, why Python for AI machine learning? Can't we use other languages?" So that's actually a great question, but also very broad. Python is definitely a great language, but there are a bunch of other languages that also do very well. One of the best things about Python is that it's really present in a lot of fields. Among them is back end web development, and machine learning, and AI stuff. I believe that assigns stuff as well. So you would find every language has its advantages and disadvantages. It's not necessarily the case that there is one language that's the absolute best language. Do you have anything to add maybe? COLTON OGDEN: I would say it's definitely the case that Python's not necessarily the fastest scripting language that exists, but it is one of probably the most readable and easy to program in, and that's a big thing. Because oftentimes, it's more-- not necessarily as important that your script run super, super fast, especially now that computers are just so fast that the time that you would get writing in another language isn't as important, but it's important that you have high level of productivity as a programmer. And being able to program in something that is very human readable, like Python, is certainly advantageous to you and to people that are especially just trying to get into the industry. It's a very approachable language. There are libraries that are compiled in C, like NumPy, and CyPY, certain other-- a lot of the big sort of data analytic libraries, they do get compiled into binaries that Python calls, that are actually in C. So you actually are getting very performant results with Python. But yeah, it's ultimately-- I would say if I were to pinpoint what it is-- and I'm not necessarily an expert, especially not in machine learning an AI, but just knowing the language-- probably ultimately comes down to a lot of really great libraries and just a very readable language. But no, certainly you could write scripts in programs in other languages that do machine learning and AI. R is very huge in statistical analysis now, even though Python is a language that's often used for that. So it just kind of-- it changes. The status quo is such that Python is great, but another language could come out any day and surpass it. Another library could come out and surpass it. KAREEM ZIDANE: That's true. We have M. Kloppenburg says, "Andre, you make me curious. Got a link?" I don't think it's hosted anywhere online. I will try to look at it. [INTERPOSING VOICES] COLTON OGDEN: Do a little bit of digging, maybe we'll bring it up on another stream maybe. KAREEM ZIDANE: Maybe. "On what date will you do the Python stream?" COLTON OGDEN: So next Monday. So that's the 19th, 11/19 at 1:00 PM. Veronica Nutting and I will-- she'll be hosting and I'll be co-hosting. She'll be doing a tour of Python. So 100 cool things to do in Python-- 100, approximately. We'll see how many we can do. KAREEM ZIDANE: This was a question from PresidentOfMars. We have the Jasong. "I like your style, Colton." COLTON OGDEN: Thanks, Jasong, much appreciated. Thank you for that. KAREEM ZIDANE: And then we have JefferyHughes, "Thanks for the answers, guys. Watching you from Morocco." COLTON OGDEN: Nice, well, thanks for tuning in all the way from Morocco. KAREEM ZIDANE: Yeah, thank you so much. COLTON OGDEN: I know we had someone else from Morocco as well. M. Kloppenburg, "I once read an article that approached it like this. System resources are cheaper than man hours. The productivity is higher in Python because of the simplicity of the language, so the man hours are cheaper. In the end, it's just cheaper." Yeah. So ultimately, human time is the most important valuable at this point in history, just given how fast computers are now. Depending on the problem that you're trying to solve, it could be the case that maybe the computational resources are important. But again, I think for most use cases and most companies, outside of maybe Google and larger, big monolithic companies that are doing massive sets of computation and large data, Python and its current limitations are perfectly sufficient. KAREEM ZIDANE: It all comes down to this, like a bunch of trade-offs, a bunch of upsides and downsides that you have to choose from and decide in what language would fit your use case best. COLTON OGDEN: Yes. LordDemure24, "Hey, all the way from Sweden. Working as a dev, but I love looking at this Twitch channel." Awesome, thanks for joining us from Sweden. I'm curious to hear what sort of dev work you're working on. KAREEM ZIDANE: Yeah, that would be great. COLTON OGDEN: We have touched every continent almost I think, and we have so many people from all over the place. It's awesome. CS50's network is vast. "It's awesome, you guys, paying the great attention to answer the questions." Oh, no, absolutely. That's the biggest thing that makes this channel awesome is kind of having that two-way communication. I said this time and time again. But making a video on YouTube is great, and we do that, but being able to actually communicate-- when we make a video for YouTube it's kind of like a script that we're following. And we sort of have everything preplanned, and we're going with the flow, and we've established it in advance. But having things like this, it's a little bit unpredictable. You don't know what someone's going to ask. You don't know what directions we're going to go, what we're going to talk about. A lot of cool things happen. In my game programming streams previously, we had folks like Andre and Edeyney who contribute and help us solve bugs live, and that's something that you can't do in a YouTube video. Normally, I would just have to cut that out, or reshoot it, or something, but we get a different approach to that here. "All continents, except Antarctica," says Andre. For now, we'll see. We'll see. Maybe we can set up an embassy in Antarctica. "I work as a system developer doing automation on a platform called Service Now. And on free time, I'm doing React and full-stack web dev. Been a dream to do games, but seemed to never find time for it." Well, tune-in on Wednesday if you want to look at the very basic game, tic-tac-toe, in Love2d. If you haven't looked at the other streams, we did Unity last week, and I've done a couple other ones on Lua and Love2d. PresidentOfMars, "Any recommendations for websites with beginner exercises or coding games currently, starting out in Python or C?" Codecademy is good. I would look at Codecademy. I'm going to go over and toss them the chat. Codecademy.com-- I believe it's .com. They're good for beginners. freeCodeCamp is good as well, but that's a lot longer, and that's oriented towards full-stack web development, not necessarily Python. Do you know any websites that are good for exercises? KAREEM ZIDANE: Code.org maybe. I know there is a bunch of tutorials that I've built in that, maybe a bunch of external resource as well if you're curious. COLTON OGDEN: What's the website? KAREEM ZIDANE: Code.org. COLTON OGDEN: Code.org? KAREEM ZIDANE: Yep. Yeah, so definitely do check that out. If you do Google "coding tutorials," I'm sure you'll also find more resources as well. COLTON OGDEN: LordDemure, "Colton, are you working as a developer or is CS50 your full-time job?" CS50 is my full-time job. I'm not currently doing any side development work. This is taking enough time, and it's interesting, because the game stuff is what I like to do. If I were to work as a developer, I'd probably try to do something either in games, which is my passion, or more pragmatically, React, or full-stack web development using React, or using whatever modern technologies people are or in the market for. LordDemure, "The other sir to your left, I never got his introduction." Would you like to introduce yourself once again? KAREEM ZIDANE: Sure. Once again, my name is Kareem Zidane, and I am a preset for here at Harvard. I work with CS50 full-time as well. I do work mainly on Cloud 9, the IDE, CS50IDE. COLTON OGDEN: Oh, that's true. We didn't talk about all the tools that you've written. You've written so many tools for us now. KAREEM ZIDANE: Yes, so I do work on the CS50IDE primarily, but I also work on all of the dev ops stuff that we have. So I do use Travis CI to continuously integrate and deploy our apps, which we have a huge number of them. We have a GitHub organization on GitHub. If you go to GitHub.com/CS50 you can find all of our open source repositories there, and you can certainly see contributions from a lot of people. COLTON OGDEN: Primarily, Kareem Zidane, but also David does a lot. David and Brian do a lot of the work probably too, right? KAREEM ZIDANE: Yeah. COLTON OGDEN: And Dan Coffey does a good sizable amount, and he'll be talking with us tomorrow on draw50. "Check io.org," looks like BasedAvon put in there. "What is the road to be a dev ops? Should I learn Java or Python for it?" KAREEM ZIDANE: I don't think it's tied to a very specific language. So dev ops are really not tied to any one specific language. Because you could have projects in Java, or Python, or any number of other languages, but you would still need to do testing as a-- we could do use different languages even for testing, if you want to, or different tools. You need to be familiar with the tools, such as Travis CI, to do stuff like continuous integration and deployment. But it's not really tied to one or two languages. COLTON OGDEN: Cool. "Incidentally, Unity's audio mixer is super awesome. Just as an idea for games stream, it'd be cool to see some ideas in that area. If you have any, perhaps a rhythm game or something along the lines of what Braid did with music that synchronizes with the time." It's been a while since I've seen Braid. I have it, but I think I've played it like five or six years ago. I did have an idea to potentially make like a Guitar Hero kind of game, or using like the keyboard, or something. So we might be able to visit that. That would be pretty cool. KAREEM ZIDANE: That would be fun. COLTON OGDEN: You want to read AssleyNuona3333's comment right there? KAREEM ZIDANE: OK. [LAUGHS] KAREEM ZIDANE: It'sDelusional says, "What's your academic background, guys?" COLTON OGDEN: Kareem, the dream. Academic background? I studied computer science at Saddleback College in California for a couple of years before moving out here to work for CS50 full-time. KAREEM ZIDANE: I did study computer science as well online. I did not study computer science formally. So most of my computer science knowledge and program knowledge are actually from online resources, like CS50 and others. COLTON OGDEN: Same. "Like Jenkins, Docker, et cetera?" says LordDemure24. KAREEM ZIDANE: Definitely, yes. If Jenkins is what you're using, you should probably familiarize yourself with Jenkins. Also, if you're using Docker, we happen to be using Docker in a lot of applications, so yeah. That's certainly something that you should look at and learn more about. COLTON OGDEN: Well, we are approaching the-- well, we are at two hours, five minutes now. So I think we're going to wrap this stream up now. So thanks so much everybody who tuned in today for Kareem's awesome tutorial-- KAREEM ZIDANE: Thank you. COLTON OGDEN: --and thorough introduction to Travis CI, and deploying apps using GitHub Pages at CI/CD. Is was a good stream, good time. We had we had a good time, and join us again tomorrow for draw50 with Dan Coffey. KAREEM ZIDANE: Thank you so much. COLTON OGDEN: Thanks, everybody. See you soon.
B1 中級 INTRO TO DEVOPS WITH TRAVIS CI - CS50 on Twitch, EP.10 (INTRO TO DEVOPS WITH TRAVIS CI - CS50 on Twitch, EP. 10) 5 0 林宜悉 發佈於 2021 年 01 月 14 日 更多分享 分享 收藏 回報 影片單字